﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using Entidades;
using Entidades.Responses;
using System.Configuration;
using Manager.App_code;
using System.Net;
using System.Threading;

namespace Manager
{
    /// <summary>
    /// Summary description for ManagerService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class ManagerService : System.Web.Services.WebService
    {
        private Semaphore semaforoClientes = new Semaphore(3, 3);
        private Semaphore semaforoAdmin = new Semaphore(1, 1);
        private const int MAXIMO_AGENTES = 5;

        #region Funciones generales
        public bool IniciarServicio()
        {
            bool exito = true;
            try
            {
                Logguer.log.Info("Servicio iniciado");
                Data.mutex = new object();
                Data.lstServidores = Rutinas.LevantarConfiguracionAgentes();
                ServerController serverCtrl = new ServerController();
                serverCtrl.IniciarServicio(Data.mutex);

                return exito;
            }
            catch (Exception ex)
            {
                Logguer.log.Error("RequestMemoria", ex);
                return false;
            }
        }
        private bool ServidorAlive(ServerNode nodo)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(nodo.URL);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                if (response.StatusCode != HttpStatusCode.OK)
                    return false;
                else
                    return true;
            }
            catch (WebException)
            {
                Logguer.log.Info("Servidor no responde :" + nodo.Nombre);
                return false;
            }
            catch (Exception ex2)
            {
                Logguer.log.Error("Error al consultar el estado del servidor.", ex2);
                return false;
            }
        }
        #endregion

        #region Funciones de Clientes
        [WebMethod]
        public Manager.AgenteService.MemoryResponse RequestMemoria(ServerNode servidor)
        {
            semaforoClientes.WaitOne();

            try
            {
                if ((Data.lstServidores.Contains(servidor)) && (Data.lstServidores.Find(o => o.URL == servidor.URL).Activo))
                {
                    if (ServidorAlive(servidor))
                    {
                        AgenteService.AgenteService servicio = new Manager.AgenteService.AgenteService();
                        servicio.Timeout = 10000;
                        servicio.Url = servidor.URL;
                        Manager.AgenteService.MemoryResponse res = servicio.ObtenerMemoria();
                        if (res == null)
                            Logguer.log.Info("Se envio una consulta de memoria retorno null");
                        return res;
                    }
                    else
                    {
                        Logguer.log.Info("Se envio una consulta de memoria a un servidor que no responde : " + servidor.URL);
                        return null;
                    }
                }
                else
                    return null;
            }
            catch (Exception ex)
            {
                Logguer.log.Error("RequestMemoria", ex);
                return null;
            }
            finally
            {
                semaforoClientes.Release();
            }
        }

        [WebMethod]
        public Manager.AgenteService.DiscoResponse RequestDisco(ServerNode servidor)
        {
            semaforoClientes.WaitOne();
            try
            {
                
                if ((Data.lstServidores.Contains(servidor)) && (Data.lstServidores.Find(o => o.URL == servidor.URL).Activo))
                {
                    if (ServidorAlive(servidor))
                    {
                        AgenteService.AgenteService servicio = new Manager.AgenteService.AgenteService();
                        servicio.Timeout = 10000;
                        servicio.Url = servidor.URL;
                        Manager.AgenteService.DiscoResponse res = servicio.ObtenerDisco();
                        if (res == null)
                            Logguer.log.Info("Se envio una consulta de memoria retorno null");
                        return res;
                    }
                    else
                    {
                        Logguer.log.Info("Se envio una consulta de disco a un servidor que no responde : " + servidor.URL);
                        return null;
                    }
                }
                else
                    return null;
            }
            catch (Exception ex)
            {
                Logguer.log.Error("RequestDisco", ex);
                return null;
            }
            finally
            {
                semaforoClientes.Release();
            }
        }

        [WebMethod]
        public Manager.AgenteService.CpuResponse RequestCpu(ServerNode servidor)
        {
            semaforoClientes.WaitOne();
            try
            {
                if ((Data.lstServidores.Contains(servidor)) && (Data.lstServidores.Find(o => o.URL == servidor.URL).Activo))
                {
                    if (ServidorAlive(servidor))
                    {
                        AgenteService.AgenteService servicio = new Manager.AgenteService.AgenteService();
                        servicio.Timeout = 10000;
                        servicio.Url = servidor.URL;
                        Manager.AgenteService.CpuResponse res = servicio.ObtenerCpu();
                        if (res == null)
                            Logguer.log.Info("Se envio una consulta de memoria retorno null");
                        return res;
                    }
                    else
                    {
                        Logguer.log.Info("Se envio una consulta de CPU a un servidor que no responde : " + servidor.URL);
                        return null;
                    }
                }
                else
                    return null;
            }
            catch (Exception ex)
            {
                Logguer.log.Error("RequestCpu", ex);
                return null;
            }
            finally
            {
                semaforoClientes.Release();
            }
        }

        [WebMethod]
        public List<ServerNode> RequestServers()
        {
            List<ServerNode> lstRetorno = new List<ServerNode>();
            semaforoClientes.WaitOne();
            try
            {
                int count = Data.lstServidores.Count;
                foreach (var servidor in Data.lstServidores)
                {
                    if (servidor.Activo)
                    {
                        if (ServidorAlive(servidor))
                            lstRetorno.Add(servidor);
                    }
                }
                return lstRetorno;
            }
            catch (Exception ex)
            {
                Logguer.log.Error("RequestServers", ex);
                return null;
            }
            finally
            {
                semaforoClientes.Release();
            }
        }
        #endregion

        #region Funciones de administracion
        [WebMethod]
        public bool AddServer(ServerNode nodo)
        {
            semaforoAdmin.WaitOne();
            try
            {
                int count = Data.lstServidores.Count;
                if (Data.lstServidores.Count < MAXIMO_AGENTES)
                {
                    nodo.Activo = true;
                    Data.lstServidores.Add(nodo);
                    Logguer.log.Info("Se agregó el servidor " + nodo.Nombre);
                    return true;
                }
                else
                {
                    Logguer.log.Info("No se agregó el servidor porque excede el limite definido.");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Logguer.log.Error("AddServer", ex);
                return false;
            }
            finally
            {
                semaforoAdmin.Release();
            }
        }

        [WebMethod]
        public bool RemoveServer(ServerNode nodo)
        {
            semaforoAdmin.WaitOne();
            try
            {
                if (Data.lstServidores.Contains(nodo))
                {
                    nodo.Activo = false;
                    Data.lstServidores.Remove(nodo);
                    Logguer.log.Info("Se ha quitado el servidor " + nodo.Nombre);
                    return true;
                }
                else
                {
                    Logguer.log.Info("No se quitó el servidor porque no está ingresado.");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Logguer.log.Error("RemoveServer", ex);
                return false;
            }
            finally
            {
                semaforoAdmin.Release();
            }
        }
        #endregion
    }
}
